#include "xmemory.h"

#ifdef WIN32

#include <windows.h>

static HANDLE g_sem = NULL;

#endif

#pragma pack(1)

typedef struct  
{
	void* pre;
	void* next;
	unsigned int size;
	unsigned char flag;
}stBlock;

#pragma pack()

static stBlock* head = NULL;

#define BLOCK_DEFAULT_SIZE	10485760	//1024*1024*10

void xlock()
{

#ifdef WIN32

	if (g_sem)
	{
		WaitForSingleObject(g_sem, INFINITE);
	}
#endif

}

void xunlock()
{

#ifdef WIN32

	if (g_sem)
	{
		ReleaseSemaphore(g_sem, 1, NULL);
	}
#endif
}

void useLocker()
{

#ifdef WIN32

	if (NULL == g_sem)
	{
		g_sem = CreateSemaphore(NULL, 1, 1, "xmemory");
	}

#endif
	
}

int remalloc(stBlock* tail)
{
	static unsigned char blockflag = 1;
	stBlock* temhead = NULL;
	stBlock* temtaill = NULL;
	char* nhead = (char*)malloc(BLOCK_DEFAULT_SIZE);
	if (NULL == nhead)
	{
		return ErrorInit;
	}
	memset(nhead, 0, BLOCK_DEFAULT_SIZE);
	temhead = (stBlock*)nhead;
	temhead->pre = tail;
	temhead->next = nhead + BLOCK_DEFAULT_SIZE - sizeof(stBlock);
	temhead->size = 0;
	temhead->flag = blockflag;

	temtaill = temhead->next;
	temtaill->pre = temhead;
	temtaill->next = NULL;
	temtaill->size = 0;
	temtaill->flag = blockflag;

	if (NULL == tail)
	{
		head = temhead;
	} 
	else
	{
		tail->next = temhead;
	}	
	blockflag++;
	return NoError;
}

void* xmalloc(int size, int* code)
{
	stBlock* blk = head;
	stBlock* nblk = NULL;
	stBlock* blknext = NULL;
	char* ret = NULL;
	if (size >= BLOCK_DEFAULT_SIZE)
	{
		if (code){
			*code = ErrorOverBlockSize;
		}
		return NULL;
	}
	xlock();
	if (NULL == head)
	{
		if(ErrorInit == remalloc(NULL) /*initMemory(BLOCK_DEFAULT_SIZE)*/){
			xunlock();
			if (code){
				*code = ErrorInit;
			}
			return NULL;
		}
		blk = head;
	}
	do 
	{
		
		int validsize = (char*)blk->next - (char*)blk - sizeof(stBlock)*2 - blk->size;
		if(validsize >= size){
			
			nblk = (stBlock*)((char*)blk+sizeof(stBlock)+blk->size);
			
			nblk->size = size;
			nblk->next = blk->next;
			nblk->pre = blk;
			nblk->flag = blk->flag;
			
			blk->next = nblk;
			break;
		}else{	
			blk = blk->next;
			if (NULL == blk->next)
			{
				if (ErrorInit == remalloc(blk))
				{
					xunlock();
					if (code){
						*code = ErrorInit;
					}
					return NULL;
				}
			}
			blknext = blk->next;
			if (blk->flag != blknext->flag)
			{
				blk = blk->next;
			}
			
		}
		
	} while (1);
	ret = (char*)nblk+sizeof(stBlock);
	memset(ret, 0, size);
	xunlock();
	if (code){
		*code = NoError;
	}
	return ret;
}

void xfree(void* data)
{
	stBlock* blk = head;
	stBlock* preblk = NULL;
	xlock();
	do 
	{
		
		if ((char*)blk+sizeof(stBlock) == data)
		{			
			preblk = blk->pre;
			preblk->next = blk->next;			
			break;
		}else
		{
			blk = blk->next;
		}
	} while (blk);
	xunlock();
}


